import sys
import os
sys.path.append(os.path.abspath(os.path.dirname(os.path.dirname(__file__))))

from app import create_app, db
from app.models.user_behavior import UserBehavior  
from app.models.users import User
from app.models.blind_box import BlindBox
from app.models.order import Order, OrderDetail
from app.models.supermarket import Supermarket

from datetime import datetime, timedelta
import random
import numpy as np

app = create_app()

def generate_behavior_data():
    """生成测试用的用户行为数据"""
    with app.app_context():
        # 获取所有用户和盲盒
        users = User.query.all()
        boxes = BlindBox.query.all()
        
        if not users or not boxes:
            print("没有足够的用户或盲盒数据，请先确保基础数据存在")
            return
        
        # 行为类型
        behavior_types = ['view', 'search', 'add_cart', 'purchase']
        
        # 生成最近90天的行为数据
        end_date = datetime.now()
        start_date = end_date - timedelta(days=90)
        
        print(f"正在生成用户行为数据从 {start_date} 到 {end_date}...")
        
        behaviors = []
        # 为每个用户生成一些行为
        for user in users:
            # 每个用户生成20-50条记录
            num_behaviors = random.randint(20, 50)
            
            for _ in range(num_behaviors):
                # 随机选择行为类型
                behavior_type = random.choice(behavior_types)
                
                # 随机选择一个盲盒，使用加权随机以模拟真实情况下的热门产品
                weights = [float(box.discount_rate) if box.discount_rate else 0.5 for box in boxes]
                box = random.choices(boxes, weights=weights, k=1)[0]
                
                # 随机时间
                random_days = random.randint(0, 90)
                random_seconds = random.randint(0, 86400)
                timestamp = end_date - timedelta(days=random_days, seconds=random_seconds)
                
                # 创建行为记录
                behavior = UserBehavior(
                    user_id=user.user_id,
                    behavior_type=behavior_type,
                    target_id=box.box_id,
                    target_type='box',
                    timestamp=timestamp,
                    session_id=f"test-session-{random.randint(1000, 9999)}",
                    ip_address=f"192.168.1.{random.randint(1, 255)}"
                )
                
                behaviors.append(behavior)
        
        # 批量添加数据
        for b in behaviors:
            db.session.add(b)
        db.session.commit()
        
        print(f"成功生成 {len(behaviors)} 条用户行为数据")

def generate_order_data():
    """生成测试用的订单数据"""
    with app.app_context():
        # 获取所有用户、盲盒和超市
        users = User.query.all()
        boxes = BlindBox.query.all()
        markets = Supermarket.query.all()
        
        if not users or not boxes or not markets:
            print("没有足够的用户、盲盒或超市数据，请先确保基础数据存在")
            return
            
        # 获取所有盲盒类别并创建类别权重字典，实现不同类别的订单分布差异
        categories = {}
        for box in boxes:
            if box.category not in categories:
                # 为不同类别分配不同的权重，模拟热门和冷门类别
                categories[box.category] = random.uniform(0.5, 2.0)
        
        print(f"发现以下类别: {list(categories.keys())}")
        
        # 生成最近365天的订单数据，增加数据量和覆盖范围
        end_date = datetime.now()
        start_date = end_date - timedelta(days=365)
        
        print(f"正在生成订单数据从 {start_date} 到 {end_date}...")
        
        orders = []
        order_details = []
        
        # 支付方式选项
        payment_methods = [1, 2, 3]  # 1-支付宝, 2-微信, 3-余额
        
        # 订单状态选项，增加已支付和已完成状态的比例
        status_options = [1, 2, 2, 3, 3, 3, 3]  # 偏向已完成订单，确保有更多有效数据
        
        # 为每个用户生成更多订单
        for user in users:
            # 每个用户生成5-15条订单
            num_orders = random.randint(5, 15)
            
            for _ in range(num_orders):
                # 随机选择一个超市
                market = random.choice(markets)
                
                # 随机时间，时间分布采用指数分布，使最近的订单更多
                days_ago = min(int(np.random.exponential(60)), 365)
                random_seconds = random.randint(0, 86400)
                create_time = end_date - timedelta(days=days_ago, seconds=random_seconds)
                
                # 随机状态和支付方式
                status = random.choice(status_options)
                payment_method = random.choice(payment_methods)
                
                # 创建订单
                order = Order(
                    user_id=user.user_id,
                    market_id=market.market_id,
                    payment_method=payment_method,
                    status=status,
                    create_time=create_time,
                    qr_code=f"http://qr.csmh.com/{random.randint(100000, 999999)}" if status > 1 else None
                )
                
                # 先把订单添加到session，这样可以在后面关联订单明细
                db.session.add(order)
                db.session.flush()  # 获取order_id但不提交
                
                orders.append(order)
                
                # 为订单添加1-5个商品明细
                num_items = random.randint(1, 5)
                total_amount = 0
                
                # 根据类别权重选择盲盒
                category_boxes = {}
                for box in boxes:
                    if box.category not in category_boxes:
                        category_boxes[box.category] = []
                    category_boxes[box.category].append(box)
                
                # 根据类别权重选择要购买的类别
                selected_categories = random.choices(
                    list(categories.keys()),
                    weights=[categories[cat] for cat in categories],
                    k=min(num_items, len(categories))
                )
                
                # 确保不同类别的出现频率不同
                order_box_ids = []
                for category in selected_categories:
                    if category in category_boxes and category_boxes[category]:
                        box = random.choice(category_boxes[category])
                        if box.box_id not in order_box_ids:  # 避免同一订单重复添加
                            order_box_ids.append(box.box_id)
                            
                            # 随机数量1-3个
                            quantity = random.randint(1, 3)
                            
                            # 使用折扣价格或者原价，并转换为float
                            price = float(box.discount_price) if box.discount_price else float(box.original_price)
                            
                            # 创建订单明细
                            order_detail = OrderDetail(
                                order_id=order.order_id,
                                box_id=box.box_id,
                                quantity=quantity,
                                price=price
                            )
                            
                            db.session.add(order_detail)
                            order_details.append(order_detail)
                            
                            # 累计订单总金额
                            item_amount = price * quantity
                            total_amount += item_amount
                
                # 如果没有选择任何商品，确保至少添加一个
                if len(order_box_ids) == 0 and boxes:
                    box = random.choice(boxes)
                    quantity = random.randint(1, 3)
                    price = float(box.discount_price) if box.discount_price else float(box.original_price)
                    
                    order_detail = OrderDetail(
                        order_id=order.order_id,
                        box_id=box.box_id,
                        quantity=quantity,
                        price=price
                    )
                    
                    db.session.add(order_detail)
                    order_details.append(order_detail)
                    
                    item_amount = price * quantity
                    total_amount += item_amount
                
                # 计算订单折扣
                voucher_discount = round(random.uniform(0, min(total_amount * 0.3, 50)), 2) if random.random() > 0.7 else 0
                shipping_fee = round(random.uniform(0, 15), 2) if random.random() > 0.5 else 0
                eco_discount = round(random.uniform(0, min(total_amount * 0.1, 20)), 2) if random.random() > 0.6 else 0
                tax_amount = round(total_amount * 0.06, 2) if random.random() > 0.8 else 0
                
                # 计算最终总金额
                final_amount = max(0, total_amount - voucher_discount - eco_discount + shipping_fee + tax_amount)
                
                # 设置订单金额信息
                order.total_amount = final_amount
                order.voucher_discount = voucher_discount
                order.shipping_fee = shipping_fee
                order.eco_discount = eco_discount
                order.tax_amount = tax_amount
                order.eco_points_earned = int(final_amount)
                
                # 每100条订单提交一次，避免内存占用过多
                if len(orders) % 100 == 0:
                    db.session.commit()
                    print(f"已生成 {len(orders)} 条订单...")
        
        # 提交所有剩余更改
        db.session.commit()
        
        # 计算并更新每个类别的销售数量统计
        category_stats = {}
        for detail in order_details:
            for box in boxes:
                if box.box_id == detail.box_id and box.category:
                    if box.category not in category_stats:
                        category_stats[box.category] = 0
                    category_stats[box.category] += detail.quantity
        
        print("类别销售统计:")
        for category, count in category_stats.items():
            print(f"  {category}: {count}件")
        
        # 更新盲盒销售数量
        for box in boxes:
            # 统计每个盲盒的销售数量
            box_details = [od for od in order_details if od.box_id == box.box_id]
            sales_count = sum(od.quantity for od in box_details)
            box.sales = sales_count
        
        db.session.commit()
        
        print(f"成功生成 {len(orders)} 条订单数据和 {len(order_details)} 条订单明细数据")
        print(f"更新了 {len(boxes)} 个盲盒的销售数量")

def generate_seasonal_order_data():
    """生成带有季节性特征的订单数据，提高销售预测分析的效果"""
    with app.app_context():
        # 获取所有用户、盲盒和超市
        users = User.query.all()
        boxes = BlindBox.query.all()
        markets = Supermarket.query.all()
        
        if not users or not boxes or not markets:
            print("没有足够的用户、盲盒或超市数据，请先确保基础数据存在")
            return
        
        # 获取所有盲盒类别
        categories = set(box.category for box in boxes if box.category)
        print(f"为以下类别添加季节性销售模式: {categories}")
        
        # 生成最近365天的数据
        end_date = datetime.now()
        start_date = end_date - timedelta(days=365)
        current_date = start_date
        
        # 创建季节性参数
        # 1. 周内模式：工作日(1-5)销量较低，周末(6-7)销量较高
        weekday_multipliers = {
            0: 0.8,  # 周一
            1: 0.85, # 周二
            2: 0.9,  # 周三
            3: 1.0,  # 周四
            4: 1.1,  # 周五
            5: 1.5,  # 周六
            6: 1.3   # 周日
        }
        
        # 2. 月度模式：模拟促销活动和节假日效应
        monthly_multipliers = {
            1: 1.0,   # 1月
            2: 0.8,   # 2月
            3: 0.9,   # 3月
            4: 1.0,   # 4月
            5: 1.2,   # 5月
            6: 1.0,   # 6月
            7: 0.8,   # 7月
            8: 0.9,   # 8月
            9: 1.1,   # 9月
            10: 1.3,  # 10月
            11: 1.4,  # 11月
            12: 1.5   # 12月
        }
        
        # 3. 季节性类别偏好
        seasonal_category_multipliers = {
            '食品': {'summer': 1.3, 'winter': 0.8},
            '饮品': {'summer': 1.8, 'winter': 0.6},
            '烘焙': {'summer': 0.7, 'winter': 1.5},
            '生鲜': {'summer': 1.3, 'winter': 0.9},
            '健康': {'summer': 1.1, 'winter': 1.1},
            '宠物': {'summer': 0.9, 'winter': 1.0},
            '日化': {'summer': 1.0, 'winter': 1.0},
            '美妆': {'summer': 1.2, 'winter': 0.8},
            '文具': {'summer': 0.7, 'winter': 1.3}
        }
        
        orders = []
        order_details = []
        
        print(f"正在生成带有季节性模式的订单数据...")
        
        # 每天生成一定数量的订单
        days_count = (end_date - start_date).days
        for day in range(days_count):
            current_date = start_date + timedelta(days=day)
            
            # 计算当天的基础订单数量
            weekday = current_date.weekday()
            month = current_date.month
            
            # 应用周和月季节性
            base_orders = 20  # 基础日订单量
            day_multiplier = weekday_multipliers[weekday] * monthly_multipliers[month]
            
            # 确定季节(简化为夏冬两季)
            is_summer = 4 <= month <= 9
            season = 'summer' if is_summer else 'winter'
            
            # 添加随机波动
            day_multiplier *= random.uniform(0.8, 1.2)
            
            # 最终当天订单数量
            day_orders_count = int(base_orders * day_multiplier)
            
            # 为当天生成订单
            for _ in range(day_orders_count):
                # 随机选择用户和超市
                user = random.choice(users)
                market = random.choice(markets)
                
                # 创建订单，大部分为已完成状态
                status = random.choices([1, 2, 3], weights=[0.1, 0.2, 0.7], k=1)[0]
                payment_method = random.randint(1, 3)
                
                order = Order(
                    user_id=user.user_id,
                    market_id=market.market_id,
                    payment_method=payment_method,
                    status=status,
                    create_time=current_date + timedelta(hours=random.randint(9, 22), 
                                                       minutes=random.randint(0, 59)),
                    qr_code=f"http://qr.csmh.com/{random.randint(100000, 999999)}" if status > 1 else None
                )
                
                db.session.add(order)
                db.session.flush()
                orders.append(order)
                
                # 为订单添加1-4个商品明细
                num_items = random.randint(1, 4)
                total_amount = 0
                
                # 当天考虑季节性的类别偏好
                seasonal_categories = []
                for cat in categories:
                    # 计算该类别在当前季节的权重
                    cat_multiplier = 1.0
                    if cat in seasonal_category_multipliers and season in seasonal_category_multipliers[cat]:
                        cat_multiplier = seasonal_category_multipliers[cat][season]
                    seasonal_categories.extend([cat] * int(cat_multiplier * 10))
                
                # 随机选择类别并添加商品
                for _ in range(num_items):
                    if not seasonal_categories:
                        break
                        
                    # 随机选择类别
                    category = random.choice(seasonal_categories)
                    
                    # 获取该类别的所有盲盒
                    category_boxes = [box for box in boxes if box.category == category]
                    if not category_boxes:
                        continue
                        
                    # 随机选择盲盒
                    box = random.choice(category_boxes)
                    
                    # 随机数量
                    quantity = random.choices([1, 2, 3], weights=[0.6, 0.3, 0.1], k=1)[0]
                    
                    # 使用折扣价格或者原价
                    price = float(box.discount_price) if box.discount_price else float(box.original_price)
                    
                    # 创建订单明细
                    order_detail = OrderDetail(
                        order_id=order.order_id,
                        box_id=box.box_id,
                        quantity=quantity,
                        price=price
                    )
                    
                    db.session.add(order_detail)
                    order_details.append(order_detail)
                    
                    # 累计订单总金额
                    item_amount = price * quantity
                    total_amount += item_amount
                
                # 如果没有添加任何商品，保证至少添加一个
                if total_amount == 0 and boxes:
                    box = random.choice(boxes)
                    quantity = 1
                    price = float(box.discount_price) if box.discount_price else float(box.original_price)
                    
                    order_detail = OrderDetail(
                        order_id=order.order_id,
                        box_id=box.box_id,
                        quantity=quantity,
                        price=price
                    )
                    
                    db.session.add(order_detail)
                    order_details.append(order_detail)
                    
                    total_amount = price * quantity
                
                # 应用折扣和额外费用
                voucher_discount = round(random.uniform(0, min(total_amount * 0.2, 30)), 2) if random.random() > 0.8 else 0
                shipping_fee = round(random.uniform(0, 10), 2) if random.random() > 0.7 else 0
                eco_discount = round(random.uniform(0, min(total_amount * 0.05, 10)), 2) if random.random() > 0.9 else 0
                
                # 计算最终订单金额
                final_amount = max(0, total_amount - voucher_discount - eco_discount + shipping_fee)
                
                # 更新订单金额信息
                order.total_amount = final_amount
                order.voucher_discount = voucher_discount
                order.shipping_fee = shipping_fee
                order.eco_discount = eco_discount
                order.eco_points_earned = int(final_amount)
            
            # 每7天提交一次，降低内存占用
            if day % 7 == 0:
                db.session.commit()
                print(f"已生成 {len(orders)} 条季节性订单数据，日期进度: {current_date.date()}")
        
        # 提交剩余更改
        db.session.commit()
        
        # 更新盲盒销售数量
        print("更新盲盒销售数量...")
        for box in boxes:
            box_details = [detail for detail in order_details if detail.box_id == box.box_id]
            sales_count = sum(detail.quantity for detail in box_details)
            box.sales += sales_count  # 注意是累加，而不是覆盖
        
        db.session.commit()
        
        print(f"成功生成 {len(orders)} 条季节性订单数据和 {len(order_details)} 条订单明细数据")
        print(f"更新了 {len(boxes)} 个盲盒的销售数量")

def clean_existing_data():
    """清理现有测试数据，以避免重复运行时的数据叠加"""
    with app.app_context():
        try:
            # 清理订单明细表
            db.session.query(OrderDetail).delete()
            
            # 清理订单表
            db.session.query(Order).delete()
            
            # 清理用户行为表
            db.session.query(UserBehavior).delete()
            
            # 重置盲盒销售数量
            for box in BlindBox.query.all():
                box.sales = 0
                
            db.session.commit()
            print("已清理现有测试数据")
        except Exception as e:
            db.session.rollback()
            print(f"清理数据时出错: {e}")

if __name__ == "__main__":
    clean_existing_data()
    generate_behavior_data()
    generate_order_data()
    generate_seasonal_order_data()  # 添加季节性订单数据
    print("所有测试数据生成完成！")
